package com.lucifer.cloud.boot.blog.chat.api;
import cn.hutool.core.util.StrUtil;
import com.lucifer.cloud.boot.blog.chat.common.RestResult;
import com.lucifer.cloud.boot.blog.chat.service.ChatService;
import com.lucifer.cloud.boot.blog.chat.service.response.ConversationVO;
import com.lucifer.cloud.boot.blog.chat.util.FileUtil;
import com.lucifer.cloud.boot.blog.nl2sql.api.Nl2SqlApi;
import com.lucifer.cloud.boot.blog.nl2sql.builder.TrainBuilder;
import com.lucifer.cloud.boot.blog.nl2sql.enumd.TrainPolicyType;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.util.List;
import java.util.Map;


@RequiredArgsConstructor
@RestController
@RequestMapping("/chat/api/conversation")
public class ChatAPI {

    final ChatClient chatClient;

    final ChatMemory chatMemory;

    final ChatService chatService;

    @Resource
    private Nl2SqlApi nl2SqlApi;





    @GetMapping("/create")
    public RestResult<ConversationVO> create(
            @RequestParam(value = "conversationType") String conversationType,
            @RequestParam(value = "tableName",required = false) String tableName
    ) {
        return RestResult.buildSuccessResult(chatService.createV2(conversationType,tableName));
    }

    @PutMapping("/edit")
    public RestResult<Void> edit(
        @RequestParam(value = "conversationId") String conversationId,
        @RequestParam(value = "title")String title) {
        chatService.editV2(conversationId, title);
        return RestResult.buildSuccessResult();
    }

    @GetMapping("/chat")
    public RestResult<String> chat(@RequestParam(value = "conversationId") String conversationId,
        @RequestParam(value = "message") String message) {
        return RestResult.buildSuccessResult(chatService.chat(conversationId,message));
    }


    @PostMapping("/chatV2")
    public RestResult chatV2(@RequestParam(value = "conversationId") String conversationId,
                             @RequestParam(value = "message") String message,
                             @RequestParam(value = "chatType") String chatType,
                             @RequestParam(value = "file",required = false) MultipartFile file,
                             @RequestParam(value = "fileUrl",required = false) String fileUrl) {
        return RestResult.buildSuccessResult(chatService.chatV3(conversationId,message,chatType,file,fileUrl));
    }


    @PostMapping("/chatV3")
    public String chatV3(@RequestParam(value = "conversationId") String conversationId,
                         @RequestParam(value = "question") String question,
                         @RequestParam(value = "data") String data) {
        return chatService.chatV4(conversationId,question,data);
    }


    @PostMapping("/voice")
    public Map voice (@RequestParam(value = "username",required = false) String username,
                      @RequestParam(value = "voiceData",required = false) MultipartFile voiceData,
                      HttpServletResponse servletResponse
    )  throws IOException{
        servletResponse.setCharacterEncoding("UTF-8");
        String localFilePath  = FileUtil.saveToLocal(voiceData);
        return chatService.voice(username,localFilePath);
    }

    @RequestMapping(method = {RequestMethod.GET,RequestMethod.POST},value = "/chatV4")
    public ResponseBodyEmitter chatV4(@RequestParam(value = "conversationId") String conversationId,
                         @RequestParam(value = "question") String question,
                         @RequestParam(value = "data") String data,
                         HttpServletResponse servletResponse) {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();
        servletResponse.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);
        servletResponse.setCharacterEncoding("UTF-8");
        Flux<ChatResponse> stream = chatService.chatV5(conversationId, question, data);
        stream.publishOn(Schedulers.boundedElastic())
                .doOnError(emitter::completeWithError)
                .doOnComplete(emitter::complete)
                .subscribe(data1 -> {
                    String text = data1.getResult().getOutput().getText();
                    try {
                        if(StrUtil.isNotEmpty(text)){
                            emitter.send(text );
                            Thread.sleep(50);
                        }
                    } catch (Exception e) {
                        emitter.completeWithError(e);
                    }
                });
        return emitter;
    }




    @PostMapping("train")
    public RestResult<Void> train(
            @RequestParam(value = "conversationId",required = false) String  conversationId,
            @RequestParam(value = "question",required = false) String  question,
            @RequestParam(value = "content",required = false) String  content,
            @RequestParam(value = "policy",required = false) String  policy,
            @RequestParam(value = "tableName",required = false) String  tableName
    ) {
        TrainBuilder builder = TrainBuilder.builder()
                .conversationId(conversationId)
                .question(question)
                .content(content)
                .policy(TrainPolicyType.valueOf(policy))
                .tableName(tableName).build();
        chatService.setTableName(conversationId, tableName);
        nl2SqlApi.train(conversationId,question,content,policy,tableName);
        return RestResult.buildSuccessResult();
    }


    @PostMapping("/nl2sql")
    public RestResult nl2sql(
            @RequestParam(value = "conversationId",required = false) String  conversationId,
            @RequestParam(value = "question",required = false) String  question,
            @RequestParam(value = "policy",required = false) String  policy,
            @RequestParam(value = "tableName",required = false) String  tableName
    ) {
        String nl2sql = nl2SqlApi.nl2sql(conversationId, question, policy, tableName);
        return RestResult.buildSuccessResult(nl2sql);
    }



    @DeleteMapping("/del")
    public RestResult<Void> del(@RequestParam(value = "conversationId")String conversationId) {
        chatService.deleteV2(conversationId);
        return RestResult.buildSuccessResult();
    }

    @GetMapping("/list")
    public RestResult<List<ConversationVO>> list() {
        return RestResult.buildSuccessResult(chatService.listV2());
    }

    @GetMapping("/get")
    public RestResult<ConversationVO> get(@RequestParam(value = "conversationId") String conversationId) {
        return RestResult.buildSuccessResult(chatService.getV2(conversationId));
    }



    @PostMapping("/uploadOss")
    public RestResult uploadOss(@RequestParam(value = "conversationId") String conversationId,
                             @RequestParam(value = "message") String message,
                             @RequestParam(value = "chatType") String chatType,
                             @RequestParam(value = "file",required = false) MultipartFile file) {
        return RestResult.buildSuccessResult(chatService.uploadOss(conversationId,message,chatType,file));
    }

}
